﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
using System.Text.RegularExpressions;
using System.IO;

using Infrastructure.Core.IOC;
using Infrastructure.Core.Loging;
using Infrastructure.Dispatcher;
using Infrastructure.Utility;

using SMG.ServiceContract.Migration;
using SMG.ServiceContract.System;
using SMG.ServiceContract.Program;
using SMG.Application.DTO.Migration;
using SMG.Application.DTO.System;
using SMG.Application.DTO.Program;
using SMG.Monitor.Domain.Models;
using SMG.Domain.Model.Program;

namespace SMG.Monitor.Domain.Services
{
    /// <summary>
    /// 上传xml播出单服务
    /// </summary>
    public class UploadXmlDispatcher : DispatcherBase
    {
        #region Fields

        /// <summary>
        /// 节目单迁移服务
        /// </summary>
        IPlayMoveService playMoveService = ServiceLocator.Instance.Resolve<IPlayMoveService>();
        IChannelService channelService = ServiceLocator.Instance.Resolve<IChannelService>();
        //日志服务
        ILogger logServer = LogService.GetInstance(LogType.Text);

        /// <summary>
        /// 每次取数据条数
        /// </summary>
        readonly Int32 count = 10;

        /// <summary>
        /// 频道列表
        /// </summary>
        IEnumerable<ChannelDto> channels;

        /// <summary>
        /// 调度配置
        /// </summary>
        DispatcherSetting dispatcherSetting;

        #endregion

        public UploadXmlDispatcher()
        {
            dispatcherSetting = new DispatcherSetting();
            channels = channelService.QueryChannelAll();
            if (channels == null) channels = new List<ChannelDto>();
        }

        #region DispatcherBase Members

        /// <summary>
        /// 间隔
        /// </summary>
        protected override long Interval
        {
            get { return dispatcherSetting.DispatcherInterval; }
        }
        /// <summary>
        /// 是否忽略一场
        /// </summary>
        protected override bool IsIgnoreException
        {
            get { return true; }
        }
        /// <summary>
        /// 是否立即启动
        /// </summary>
        protected override bool IsStartImmediate
        {
            get { return true; }
        }

        /// <summary>
        /// 调度方法
        /// </summary>
        public override void Dispatching()
        {
            var plays = playMoveService.GetWaitUploadXmlPlay(count);
            while (plays != null && plays.Any()) {
                try
                {
                    foreach (var play in plays) {
                        try
                        {
                            #region 数据校验

                            if (String.IsNullOrEmpty(play.PlayContent))
                            {
                                play.LockStatus = 0;
                                play.SendXmlFlag = 9;   //9：异常失败
                                playMoveService.SetWaitUploadXmlPlay(play);
                                continue;
                            }
                            
                            var channel = channels.FirstOrDefault(c => c.ChannelId == play.ChannelId);
                            if (channel == null) {
                                play.LockStatus = 0;
                                play.SendXmlFlag = 9;
                                playMoveService.SetWaitUploadXmlPlay(play);
                                continue;
                            }
                            //获取频道设备列表
                            var devices = channelService.GetDeviceByChannel(channel.ChannelId);
                            if (devices == null || !devices.Any())
                            {
                                play.LockStatus = 0;
                                play.SendXmlFlag = 9;
                                playMoveService.SetWaitUploadXmlPlay(play);
                                continue;
                            }

                            #endregion

                            #region 获取设备列表

                            List<DeviceDto> masterDevices = null, slaveDevices = null;
                            if (!String.IsNullOrEmpty(channel.DeviceIdsMaster)) {
                                var ids = channel.DeviceIdsMaster.Split(new Char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                                if (ids != null && ids.Length > 0) {
                                    masterDevices = new List<DeviceDto>();
                                    ids.Distinct().ToList().ForEach(id =>
                                    {
                                        masterDevices.Add(devices.FirstOrDefault(d => d.DeviceId == id));
                                    });
                                }
                            }
                            if (!String.IsNullOrEmpty(channel.DeviceIdsSlave))
                            {
                                var ids = channel.DeviceIdsSlave.Split(new Char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                                if (ids != null && ids.Length > 0)
                                {
                                    slaveDevices = new List<DeviceDto>();
                                    ids.Distinct().ToList().ForEach(id =>
                                    {
                                        slaveDevices.Add(devices.FirstOrDefault(d => d.DeviceId == id));
                                    });
                                }
                            }

                            if ((masterDevices == null || !masterDevices.Any()) && (slaveDevices == null || !slaveDevices.Any()))
                                throw new Exception("该频道没有设置有效的节目单存储设备");

                            #endregion

                            #region 文件上传主设备服务器

                            if (masterDevices != null && masterDevices.Any()) {
                                foreach (var device in masterDevices) {
                                    var path = String.Format(@"{0}\{1}", device.MountPath, channel.FolderListMaster);
                                    //先创建txt文件，文件写完以后再重命名为xml文件
                                    var fakeName = String.Format(@"{0}-{1}-{2}.temp", play.PlayDate, play.ChannelId, play.PlayVersion);
                                    var realName = String.Format(@"{0}-{1}-{2}.xml", play.PlayDate, play.ChannelId, play.PlayVersion);
                                    var fakePath = String.Format(@"{0}\{1}", path, fakeName);
                                    var realPath = String.Format(@"{0}\{1}", path, realName);
                                    if (!CreateDirectory(path))
                                        continue;

                                    //写xml文件到对应目录下
                                    using (var stream = new FileStream(fakePath, FileMode.Create))
                                    {
                                        using (var writer = new StreamWriter(stream, Encoding.Default))
                                        {
                                            writer.Write(play.PlayContent);
                                        }
                                    }
                                    //重命名文件
                                    if (File.Exists(realPath)) File.Delete(realPath);
                                    File.Move(fakePath, realPath);
                                    if (!File.Exists(realPath))
                                        throw new Exception("主设备文件上传失败！");
                                    File.Delete(fakePath);
                                }
                            }

                            #endregion

                            #region 文件上传备用服务器

                            if (slaveDevices != null && slaveDevices.Any())
                            {
                                foreach (var device in slaveDevices)
                                {
                                    var path = String.Format(@"{0}\{1}", device.MountPath, channel.FolderListSlave);
                                    //先创建txt文件，文件写完以后再重命名为xml文件
                                    var fakeName = String.Format(@"{0}-{1}-{2}.temp", play.PlayDate, play.ChannelId, play.PlayVersion);
                                    var realName = String.Format(@"{0}-{1}-{2}.xml", play.PlayDate, play.ChannelId, play.PlayVersion);
                                    var fakePath = String.Format(@"{0}\{1}", path, fakeName);
                                    var realPath = String.Format(@"{0}\{1}", path, realName);
                                    if (!CreateDirectory(path))
                                        continue;

                                    //写xml文件到对应目录下
                                    using (var stream = new FileStream(fakePath, FileMode.Create))
                                    {
                                        using (var writer = new StreamWriter(stream, Encoding.Default))
                                        {
                                            writer.Write(play.PlayContent);
                                        }
                                    }
                                    //重命名文件
                                    if (File.Exists(realPath)) File.Delete(realPath);
                                    File.Move(fakePath, realPath);
                                    if (!File.Exists(realPath))
                                    {
                                        //写入成功:更改记录状态，删除临时文件
                                        throw new Exception("备用设备文件上传失败！");
                                    }
                                    File.Delete(fakePath);
                                }
                            }

                            #endregion

                            //写入成功:更改记录状态
                            play.LockStatus = 0;
                            play.SendXmlFlag = 1;
                        }
                        catch (Exception ex)
                        {
                            play.LockStatus = 0;
                            play.SendXmlFlag = 9;
                            logServer.Info("UploadXmlDispatcher.Dispatching.ExceptionIn", ex.Message);
                        }
                        finally {
                            playMoveService = ServiceLocator.Instance.Resolve<IPlayMoveService>();
                            playMoveService.SetWaitUploadXmlPlay(play);
                        }
                    }
                    plays = playMoveService.GetWaitUploadXmlPlay(count);
                }
                catch (Exception ex) {
                    logServer.Info("UploadXmlDispatcher.Dispatching.ExceptionOut", ex.Message);
                }
            }
        }

        #endregion

        #region Pirvate Methods

        /// <summary>
        /// 创建路径
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private Boolean CreateDirectory(String path) {
            Boolean result = false;
            if (Directory.Exists(path)) return true;
            try
            {
                Directory.CreateDirectory(path);
                result = true;
            }
            catch (Exception ex) {
                result = false;
            }
            return result;
        }

        #endregion
    }
}
